//! Fault injection utilities for testing error scenarios.
//!
//! Provides configurable failpoints that can trigger specific error conditions during testing.
//! Failpoints support different retry policies to test error handling and recovery behavior.

use fail::fail_point;

use crate::bail;
use crate::error::{ErrorKind, EtlResult};

pub const START_TABLE_SYNC_BEFORE_DATA_SYNC_SLOT_CREATION: &str =
    "start_table_sync.before_data_sync_slot_creation";
pub const START_TABLE_SYNC_DURING_DATA_SYNC: &str = "start_table_sync.during_data_sync";

/// Executes a configurable failpoint for testing error scenarios.
///
/// When the failpoint is active, and it's set to return an error, this function generates an [`EtlError`] with
/// the specified retry policy. The retry behavior can be controlled through
/// the failpoint parameter:
///
/// - `"no_retry"` - Creates an error that should not be retried
/// - `"manual_retry"` - Creates an error requiring manual intervention
/// - `"timed_retry"` - Creates an error that can be automatically retried
/// - Any other value defaults to `"no_retry"`
///
/// Returns `Ok(())` when the failpoint is inactive, allowing normal execution.
pub fn etl_fail_point(name: &str) -> EtlResult<()> {
    fail_point!(name, |parameter| {
        let mut error_kind = ErrorKind::WithNoRetry;
        if let Some(parameter) = parameter {
            error_kind = match parameter.as_str() {
                "no_retry" => ErrorKind::WithNoRetry,
                "manual_retry" => ErrorKind::WithManualRetry,
                "timed_retry" => ErrorKind::WithTimedRetry,
                _ => ErrorKind::WithNoRetry,
            }
        }

        bail!(
            error_kind,
            "Failpoint triggered an error",
            format!("Failpoint '{}' returned an error", name)
        );
    });

    Ok(())
}
